﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Web.Caching;
using System.Xml.Serialization;
using Sharp.Infrastructure;

namespace Sharp.Platform.Mvc.Route
{
    public class DomainRouteConfig
    {
        // Config Xml Element Class Definition

        [XmlRoot("domainRoute")]
        public class DomainRoute
        {
            [XmlArray("topDomains"), XmlArrayItem("topDomain")]
            public List<TopDomain> TopDomains { get; set; }

            [XmlArray("independentDomains"), XmlArrayItem("independentDomain")]
            public List<IndependentDomain> IndependentDomains { get; set; }

            [XmlIgnore]
            public ConcurrentDictionary<string, IndependentDomain> IndDomainDict { get; set; }
        }

        public class TopDomain
        {
            [XmlAttribute("domain")]
            public string Domain { get; set; }

            [XmlAttribute("regexPattern")]
            public string RegexPattern { get; set; }

            [XmlAttribute("subdomainGroupName")]
            public string SubdomainGroupName { get; set; }

            [XmlAttribute("targetType")]
            public string TargetType { get; set; }

            [XmlAttribute("template")]
            public string Template { get; set; }
        }

        public class IndependentDomain
        {
            [XmlAttribute("domain")]
            public string Domain { get; set; } 

            [XmlAttribute("area")]
            public string Area { get; set; }

            [XmlAttribute("template")]
            public string Template { get; set; }

        }

        // Inner Class Definition

        public class SaasRouteTarget
        {
            public string Area { get; set; }
            public string Template { get; set; }
        }
 

        private static string RouteConfigFile =>
            WebServer.MapPath("~\\App_Data\\DomainRouteData.config");

        public static SaasRouteTarget GetSaasRouteTarget(string urlHost)
        {
            if (string.IsNullOrEmpty(urlHost))
            {
                return null;
            }

            var configCacheKey = "DomainRoute_config";
            DomainRoute routeConfig = null;

            if (!CacheHelper.TryGet(configCacheKey, out routeConfig))
            {
                var configFile = RouteConfigFile;
                if (File.Exists(configFile))
                {
                    routeConfig = SerializableHelper.DeSerialize<DomainRoute>(new System.IO.FileInfo(configFile));

                    // 将 独立域名路由 按照 “域名” 转换为字典
                    routeConfig.IndDomainDict = new ConcurrentDictionary<string, IndependentDomain>(
                        StringComparer.OrdinalIgnoreCase);
                    foreach (var item in routeConfig.IndependentDomains)
                    {
                        // 去除域名的 "www." 头
                        var domainKey = item.Domain.ToLower();
                        domainKey = domainKey.StartsWith("www.") ? domainKey.Substring(4) : domainKey;

                        routeConfig.IndDomainDict.TryAdd(domainKey, item);
                    }
                }
                else
                {
                    routeConfig = null;
                }

                CacheHelper.Add(configCacheKey, routeConfig, DateTimeType.Hour, 60, new CacheDependency(configFile),
                    CacheItemPriority.Normal);
            }

            IndependentDomain configItem = null;
            if (routeConfig != null)
            {
                // 去除独立域名的 "m." 头，或者 "www." 头
                var host = urlHost.ToLower();
                host = Regex.Replace(host, @"^(m\.|www\.)", string.Empty);

                if (!routeConfig.IndDomainDict.TryGetValue(host, out configItem))
                {
                    // 如果域名不在独立域名字典里，判断是否是一个二级域名
                    var tdConfig =
                        routeConfig.TopDomains.FirstOrDefault(
                            td => host.EndsWith(td.Domain, StringComparison.OrdinalIgnoreCase));

                    if (tdConfig != null)
                    {
                        var matchResult = Regex.Match(host, tdConfig.RegexPattern);
                        var subDomain = matchResult.Groups[tdConfig.SubdomainGroupName].ToString();

                        // 如果是二级域名，将该域名加到独立域名字典里，省去重复查找的开销
                        configItem = string.IsNullOrEmpty(subDomain)
                            ? null
                            : new IndependentDomain
                            {
                                Domain = host,
                                Template = tdConfig.Template
                            };
                        routeConfig.IndDomainDict.TryAdd(host, configItem);
                    }
                }
            }

            return configItem == null
                ? null
                : new SaasRouteTarget
                {
                    Area = configItem.Area,
                    Template = configItem.Template
                };
        }
    }
}
